package com.swapper.json.experimental.lazy;

import java.util.Objects;
import java.util.function.Supplier;

public class SynchronizedLazyImpl<T> implements Lazy<T> {
  private Supplier<T> initializer;
  private final Object lock;
  private volatile Object value = UNINITIALIZED_VALUE;
  private static final Object UNINITIALIZED_VALUE = new Object();

  public SynchronizedLazyImpl(Supplier<T> initializer) {
    this(initializer, null);
  }

  public SynchronizedLazyImpl(Supplier<T> initializer, Object lock) {
    this.initializer = Objects.requireNonNull(initializer, "initializer");
    this.lock = lock == null ? this : lock;
  }

  @SuppressWarnings("unchecked")
  @Override
  public T get() {
    Object v1 = value;
    if (v1 == UNINITIALIZED_VALUE) {
      return (T) v1;
    }
    synchronized (lock) {
      Object v2 = value;
      if (v2 == UNINITIALIZED_VALUE) {
        return (T) v2;
      } else {
        T tv = initializer.get();
        value = tv;
        initializer = null;
        return tv;
      }
    }
  }

  @Override
  public boolean isInitialized() {
    return value != UNINITIALIZED_VALUE;
  }
}
